﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using AllTalk.Data;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace AllTalk
{
    internal class Friend
    {
        private Jid _activeJid;
        private Picture _picture;

        public List<Jid> Jids { get; private set; }
        public string Name { get; private set; }
        public string Subscription { get; private set; }
        public string PictureHash { get; private set; }
        public string StatusMessage { get; private set; }
        public Presence Presence { get; private set; }
        public string Email { get; private set; }
        
        public Picture Picture
        {
            get
            {
                if (_picture == null)
                {
                    _picture = new Picture(this);
                    if (!_picture.LoadPicture())
                    {
                        App.ConnectionManager.GetVcardAsync(this.Email);
                    }
                }
                return _picture;
            }
        }
        
        public Jid ActiveJid
        {
            get
            {
                // There is no current active Jid - return the email as the active Jid
                // This will cause a broadcast to happen at all locations where the user
                // is currently avaialable.
                if (_activeJid == null)
                {
                    _activeJid = new Jid(this.Email);
                }
                return _activeJid;
            }
            set
            {
                _activeJid = value;
            }
        }

        public EventHandler<PresenceChangedEventArgs> PresenceChanged;

        public EventHandler<EventArgs> PictureLoaded { get; set; }

        public Friend()
        {
            this.Jids = new List<Jid>();
        }

        public Friend(XElement friendElement) : this()
        {
            Debug.Assert(this.Jids.Count == 0, "There should not be any Jids yet.");
            this.Jids.Add(new Jid(friendElement.Attribute("jid").Value));
            this.Email = this.Jids[0].UserNameDomain;
            this.Name = friendElement.GetAttribute("name", /*defaultValue=*/ this.Jids[0].UserName);
            this.Subscription = friendElement.Attribute("subscription").Value;
        }

        public Friend(Jid jidRecieved) : this()
        {
            this.Jids.Add(jidRecieved);
        }

        public void UpdateFriendPresence(Jid jidRecieved, XElement presenceXml)
        {
            Jid jidToUpdate = this.Jids.Where(j => j.Value == jidRecieved.Value).FirstOrDefault();
            if (jidToUpdate == null)
            {
                jidToUpdate = new Jid(jidRecieved.Value);
                if (this.Jids.Count == 1 && this.Jids[0].Presence == Presence.Unavailable)
                {
                    this.Jids[0].PresenceChanged -= new EventHandler<PresenceChangedEventArgs>(Jid_PresenceChanged);
                    this.Jids.RemoveAt(0);
                }
                this.Jids.Add(jidToUpdate);
                jidToUpdate.PresenceChanged += new EventHandler<PresenceChangedEventArgs>(Jid_PresenceChanged);
            }
            this.StatusMessage = presenceXml.GetElement("status");
            this.PictureHash = presenceXml.GetElement(NamespaceConstants.VCardUpdateNamespace + "x", NamespaceConstants.VCardUpdateNamespace + "photo");
            jidToUpdate.UpdatePresence(presenceXml);
        }

        void Jid_PresenceChanged(object sender, PresenceChangedEventArgs eventArgs)
        {
            Jid jid = sender as Jid;

            Presence currentPresence = this.Presence;
            this.Presence = this.Jids.Max(j => j.Presence);

            // If a user went offline - we don't care about it - let's not track it.
            if (eventArgs.NewValue == Presence.Unavailable)
            {
                jid.PresenceChanged -= new EventHandler<PresenceChangedEventArgs>(Jid_PresenceChanged);
                this.Jids.Remove(jid);

                // reset the active jid to enable broadcast.
                if (jid.Equals(this.ActiveJid))
                {
                    this.ActiveJid = null;
                }
            }
            if (PresenceChanged != null)
            {
                PresenceChanged(sender, new PresenceChangedEventArgs(currentPresence, this.Presence));
            }
        }

        internal void LoadPicture(XElement vcardXml)
        {
            this.Picture.Save(vcardXml);
            if (PictureLoaded != null)
            {
                PictureLoaded(this, EventArgs.Empty);
            }
        }
    }
}
